package org.infodavid.common.persistence.impl;

import java.io.InputStream;
import java.io.Reader;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Arrays;
import java.util.Scanner;
import java.util.Stack;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.infodavid.common.persistence.SqlScriptHelper;

/**
 * The Class SqlScriptHelperImpl.
 */
public final class SqlScriptHelperImpl extends SqlScriptHelper {

  /** The Constant LOGGER. */
  private static final Log LOGGER = LogFactory.getLog(SqlScriptHelperImpl.class);

  /** The Constant DELIMITERS. */
  private static final String DELIMITERS = "(;(\r)?\n)|(--\n)";

  /** The statement separator. */
  private final String statementSeparator = ";";

  /**
   * The Constructor.
   */
  private SqlScriptHelperImpl() {
    super();
  }

  /**
   * Parses the.
   * @param scanner the scanner
   * @return the string[]
   */
  public String[] parse(final Scanner scanner) {
    final Stack<String> lines = new Stack<String>();
    int spacePosition;

    scanner.useDelimiter(DELIMITERS);

    while (scanner.hasNext()) {
      String line = scanner.next();

      if (line.startsWith("/*!") && line.endsWith("*/")) {
        spacePosition = line.indexOf(' ');
        line = line.substring(spacePosition + 1, line.length() - " */".length());
      }
      else if (line.startsWith("/**") && line.endsWith("*/")) {
        spacePosition = line.indexOf(' ');
        line = line.substring(spacePosition + 1, line.length() - " */".length());
      }

      if (line.trim().length() > 0) {
        if (!line.endsWith(statementSeparator)) {
          line = line + statementSeparator;
        }

        lines.add(line);
      }
    }

    if (LOGGER.isDebugEnabled()) {
      LOGGER.debug("Resulting statements: " + Arrays.toString(lines.toArray()));
    }

    return lines.toArray(new String[lines.size()]);
  }

  /*
   * (non-Javadoc)
   * @see org.infodavid.common.persistence.SqlScriptHelper#parse(java.lang.String)
   */
  @Override
  public String[] parse(final String source) {
    return parse(new Scanner(source));
  }

  /*
   * (non-Javadoc)
   * @see org.infodavid.common.persistence.SqlScriptHelper#parse(java.io.Reader)
   */
  @Override
  public String[] parse(final Reader in) {
    return parse(new Scanner(in));
  }

  /*
   * (non-Javadoc)
   * @see org.infodavid.common.persistence.SqlScriptHelper#parse(java.io.InputStream)
   */
  @Override
  public String[] parse(final InputStream in) {
    return parse(new Scanner(in));
  }

  /*
   * (non-Javadoc)
   * @see org.infodavid.common.persistence.SqlScriptHelper#execute(java.sql.Connection,
   * java.lang.String[])
   */
  @Override
  public int execute(final Connection conn, final String[] lines) throws SQLException {
    Statement st = null;
    int count = 0;

    if (LOGGER.isDebugEnabled()) {
      LOGGER.debug("Executing statements of the script");
      LOGGER.debug(Arrays.toString(lines));
    }

    try {
      for (final String line : lines) {
        if (StringUtils.isNotEmpty(line)) {
          if (LOGGER.isDebugEnabled()) {
            LOGGER.debug("Executing statement: " + line);
          }

          st = conn.createStatement();

          st.execute(line);
          count++;

          PersistenceUtil.release(st);
        }
      }
    }
    finally {
      LOGGER.info(count + " statements executed with success");

      if (st != null) {
        PersistenceUtil.release(st);
      }
    }

    return count;
  }
}
